﻿using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;

namespace WcfRestService1.ExceptionHandling
{
    public class GeneralErrorHandler : IErrorHandler
    {
        /// <summary>
        /// 处理异常的方法代理. 
        /// <para>通常情况下这个方法代理应该返回false, 以使其他处理异常的方法代理能继续处理这个异常.</para>
        /// </summary>
        public readonly Func<Exception, bool> FnHandleError;

        /// <summary>
        /// 根据异常生成返回到客户端的错误信息的方法代理.
        /// </summary>
        public readonly Func<Exception, object> FnGetFaultDetails;

        /// <summary>
        /// 创建一个GeneralErrorHandler新实例.
        /// </summary>
        /// <param name="fnGetFaultDetails">根据异常生成返回到客户端的错误信息的方法代理.</param>
        /// <param name="fnHandleError">
        /// 处理异常的方法代理. 
        /// <para>通常情况下这个方法代理应该返回false, 以使其他处理异常的方法代理能继续处理这个异常.</para>
        /// </param>
        public GeneralErrorHandler(Func<Exception, bool> fnHandleError, Func<Exception, object> fnGetFaultDetails)
        {
            FnHandleError = fnHandleError;
            FnGetFaultDetails = fnGetFaultDetails;
        }

        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            if (FnHandleError == null)
                return false; //returns false so the other Error Handlers can do sth with the error.

            return FnHandleError(error);
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            //如果你只是想捕获并记录所有的异常, 并打算向客户端发送所有的错误信息,
            //你可以把以下代码用一句fault = null;代替


            //if we set fault = null, raw error will be sent to client(http status won't be 200 OK);
            //  otherwise, if you provided fault message, http status will be 200 OK, and client will receive the fault message instead an error.

            var isJson = true;
            var context = WebOperationContext.Current;
            if (null != context && null != context.OutgoingResponse && null != context.OutgoingResponse.Format)
                isJson = context.OutgoingResponse.Format.Value == WebMessageFormat.Json;

            var faultDetails = null == FnGetFaultDetails ? null : FnGetFaultDetails(error);
            var bodyWriter = new FaultBodyWriter(faultDetails, isJson);
            fault = Message.CreateMessage(version, string.Empty, bodyWriter);

            var bodyFormatProperty = new WebBodyFormatMessageProperty(isJson ? WebContentFormat.Json : WebContentFormat.Xml);
            fault.Properties[WebBodyFormatMessageProperty.Name] = bodyFormatProperty;

            if (isJson)
                context.OutgoingResponse.ContentType = "application/json";
        }

        #endregion
    }
}